Skip to content

eth: implement EIP-7975 (eth/70 - partial block receipt lists)#33153

Merged
fjl merged 54 commits into
ethereum:masterfrom
healthykim:bs/eip7975-peer
Mar 30, 2026
Merged

eth: implement EIP-7975 (eth/70 - partial block receipt lists)#33153
fjl merged 54 commits into
ethereum:masterfrom
healthykim:bs/eip7975-peer

Conversation

@healthykim
Copy link
Copy Markdown
Contributor

@healthykim healthykim commented Nov 11, 2025

This is a draft PR to add support for EIP-7975.
Overall changes

  • Each response is buffered in the peer’s receipt buffer when the lastBlockIncomplete field is true.
  • Continued request uses the same request id of its original request(RequestPartialReceipts).
  • Partial responses are verified in validateLastBlockReceipt.
  • Even if all receipts for partial blocks of the request are collected, those partial results are not sinked to the downloader, to avoid complexity. This assumes that partial response and buffering occur only in exceptional cases. (The complexity added to the queue can be checked in 1f32d8959)

@healthykim healthykim changed the title WIP: add eip-7975 EIP-7975: eth/70 - partial block receipt lists Nov 15, 2025
@healthykim healthykim changed the title EIP-7975: eth/70 - partial block receipt lists eth: implement EIP-7975 (eth/70 - partial block receipt lists) Nov 15, 2025
@healthykim healthykim marked this pull request as ready for review November 18, 2025 13:37
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/dispatcher.go Outdated
Comment thread eth/protocols/eth/peer.go
Comment thread eth/protocols/eth/peer.go
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread rlp/raw.go
Comment thread eth/protocols/eth/peer.go Outdated

// RequestReceipts fetches a batch of transaction receipts from a remote node.
func (p *Peer) RequestReceipts(hashes []common.Hash, sink chan *Response) (*Request, error) {
func (p *Peer) RequestReceipts(hashes []common.Hash, gasUsed []uint64, sink chan *Response) (*Request, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a short comment that explains gasUsed in the function godoc comment.

Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/handlers.go
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
}

// Verify that the total number of transactions delivered is under the limit.
if uint64(previousTxs+lastReceipts.items.Len()) > gasUsed/21_000 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIP-2780 changes the intrinsic cost of transactions to 4500gas. To apply this, we have to find a way to relay the block timestamp of the block to which this receipt list is related. Then we can perform a fork parameter lookup to find the correct cost. It's annoying but we need this check.

Comment thread eth/protocols/eth/peer.go Outdated
Comment on lines +533 to +548
content, _, err := rlp.SplitList(it.Value())
if err != nil {
return 0, fmt.Errorf("invalid receipt structure: %v", err)
}
rest := content
for range 3 {
_, _, rest, err = rlp.Split(rest)
if err != nil {
return 0, fmt.Errorf("invalid receipt structure: %v", err)
}
}
logsContent, _, err := rlp.SplitList(rest)
if err != nil {
return 0, fmt.Errorf("invalid receipt logs: %v", err)
}
log += uint64(len(logsContent))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should live in a function in receipt.go. It is basically traversing the receipt object to find the logs data that should count towards the gas limit check.

Comment thread eth/protocols/eth/peer_test.go Outdated
Comment on lines +428 to +431
tresp = tracker.Response{ID: delivery.RequestId, MsgCode: ReceiptsMsg, Size: delivery.List.Len()}
if err = peer.tracker.Fulfil(tresp); err != nil {
t.Fatalf("tracker.Fulfil failed: %v", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think invoking the tracker here does not have a purpose in the test. If you want to test the handler behavior as it is done by handler, you basically have to invoke the handler function directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we reuse IDs the tracker would raise an ID collision error if a request with the same ID was not fulfilled.

However, I agree that the test itself is not well structured, and its is also strange to be in peer_test.go. Since wwe already have devp2p tests and TestGetBlockPartialReceipt, I think it is okay to remove these tests.

@rjl493456442 rjl493456442 modified the milestones: 1.17.2, 1.17.3 Mar 30, 2026
@fjl fjl changed the title eth, cmd, rlp: implement EIP-7975 (eth/70 - partial block receipt lists) eth: implement EIP-7975 (eth/70 - partial block receipt lists) Mar 30, 2026
@fjl fjl merged commit 965bd6b into ethereum:master Mar 30, 2026
5 of 7 checks passed
diega added a commit to diega/go-ethereum-classic that referenced this pull request May 11, 2026
Upstream v1.17.3 (PR ethereum#33153, commit 965bd6b, eth/70 partial receipt
lists) made chain.go unconditionally load testdata/txinfo.json, which
carries the LargeReceiptBlock hint used by ETH70 receipt tests. ETC's
PoW chain doesn't expose ETH70 so LargeReceiptBlock has no meaningful
value, but the file still has to exist for NewChain to succeed in the
ethtest suite. Provide a stub with the field as null; the dependent
test paths (suite.go LargeReceiptBlock checks) gracefully skip when
the value is nil.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants